/*  功能:主机通信
    xx
    xx
*/
#include "UDP_Host.h"
#include "bsp_port.h"
#include "bsp_RingBuffer.h"

// 数据包协议  主机
// 与下位机通信

#define RB_FIFO_MAX_SIZE (32)
RingBuffer_Typedef UART02_RETAINER_BUF; // 从机  跟小板子通信

#define bsp_Send_Bytes bsp_USART1_SendBytes

#define ERR_SHOW_COM_RANGE (Err_Obey = 1) // 跟下位机板通信故障 显示
#define ERR_HIDE_COM_RANGE (Err_Obey = 0) // 跟下位机板通信故障 隐藏

extern RingBuffer_Typedef UART02_RETAINER_BUF;

UDP_DataFrame_Typedef UDP_RxBuf; // 读取
UDP_DataFrame_Typedef UDP_TxBuf; // 接收

uint8_t Rx_buf[RB_FIFO_MAX_SIZE]; // 从缓存区里读到的数据

/*  @brief  CRC8校验
    @param  *p_buffer
            数据
    @param  buf_size
            数据长度
    @return 无
    @property 无
*/
static uint8_t crc8(uint8_t *p_buffer, uint16_t buf_size)
{
    uint8_t crc = 0;
    uint8_t i = 0;

    if (buf_size <= 0)
    {
        return crc;
    }

    while (buf_size--)
    {
        for (i = 0x80; i != 0; i /= 2)
        {
            if ((crc & 0x80) != 0)
            {
                crc *= 2;
                crc ^= 0x07;
            }
            else
            {
                crc *= 2;
            }

            if ((*p_buffer & i) != 0)
            {
                crc ^= 0x07;
            }
        }

        p_buffer++;
    }

    return crc;
}
uint8_t CRC8(uint8_t *p_buffer, uint16_t buf_size)
{
    return crc8(p_buffer, buf_size);
}

/*  @brief  等待接收数据
     @param  *buff
             接收数据的BUFF
     @return 无
     @property 无
 */
uint8_t UDP_AwaitReceiveData(uint8_t *buff)
{
    uint8_t Delay_Time = 20; // 超时计数器  计算时间的方法=1(s)/波特率*(字节数*8+1+1)  这里把时间放长一些，时间=Delay_Time*5ms
    uint8_t Datalen = 0;
    uint8_t UDP_Cnt;

    while (1)
    {
        UDP_Cnt = RB_ReadBytes(&UART02_RETAINER_BUF, buff + Datalen, RB_FIFO_MAX_SIZE - Datalen);
        if (UDP_Cnt)
        {
            Datalen += UDP_Cnt;
            if (Datalen >= RB_FIFO_MAX_SIZE)
            {
                break;
            }
            UDP_delay(5);
        }
        else
        {
            if (Delay_Time && Datalen == 0)
            {
                Delay_Time--;
                UDP_delay(5);
            }
            else
            {
                break;
            }
        }
    }
    return (Datalen);
}

/*  @brief  读取全部数据
    @param  *data
            读取到的数据
    @param  again
            请求失败后重发次数
    @return 是否成功
    @property 无
*/
UDP_ERR_TYPEDEF UDP_ReadAllData(uint8_t *data, uint8_t again)
{
    UDP_ERR_TYPEDEF returnValue;
    uint8_t Datalen = 0;

    uint8_t udp_CMD = 0x02; // 固定的命令字 CMD
    uint8_t SendBuff[32];   // 待发送的buff

    SendBuff[0] = 0xF7;                            // 帧头
    SendBuff[1] = 0xAA;                            // 地址 这里固定写0xAA
    SendBuff[2] = 0x06;                            // 整帧的长度
    SendBuff[3] = udp_CMD;                         // 命令字
    SendBuff[4] = 0x01;                            // 数据
    SendBuff[5] = CRC8(SendBuff, SendBuff[2] - 1); // CRC8校验值

    // while (RB_ReadBytes(&UART02_RETAINER_BUF, Rx_buf + Datalen, RB_FIFO_MAX_SIZE - Datalen))
    //     ;

    bsp_Send_Bytes(SendBuff, SendBuff[2]); // 发送数据

    for (uint8_t i = 1; i <= again; i++)
    {
        /**************************    等待接收回包的数据  ***************************/
        Datalen = UDP_AwaitReceiveData(Rx_buf);
        /***************************    处理回包中的数据  *********************************/
        if (Datalen >= 4 && CRC8(Rx_buf, Datalen - 1) == Rx_buf[Datalen - 1]) // 数据长度大于等于5，并且CRC8校验OK
        {
            if (Rx_buf[0] != 0xF7 || Rx_buf[1] != 0xAA) // 帧头、地址 校验
            {
                returnValue = UDP_ERR;
            }

            if (Rx_buf[3] == (udp_CMD | 0x80)) // 如果命令字验证正确，进行数据提取
            {
                for (uint8_t i = 0; i < Rx_buf[2] - 5; i++) // 存数据
                {
                    data[i] = Rx_buf[i + 4];
                }
                returnValue = UDP_OK;
                return UDP_OK;
            }
            else
            {
                returnValue = UDP_ERR_CMD;
            }
        }
        if (i == again)
        {
            return UDP_ERR_CRC;
        }

        bsp_Send_Bytes(SendBuff, SendBuff[2]); // 重新发送数据

        returnValue = UDP_ERR_CRC;
    }
    return (returnValue);
}

/*  @brief  金属探测 打开关闭
    @param  value
            关闭 、打开   SHUT_s 、OPEN_s
    @param  again
            请求失败后重发次数
    @return 无
    @property 无
*/
UDP_ERR_TYPEDEF UDP_SetProbe_EN(SWITCH_E value, uint8_t again)
{
    UDP_ERR_TYPEDEF returnValue; // 返回值
    uint8_t Datalen;

    uint8_t udp_CMD = 0x01; // 命令字
    uint8_t SendBuff[32];   // 待发送的buff

    SendBuff[0] = 0xF7;                            // 帧头
    SendBuff[1] = 0xAA;                            // 地址 这里固定写0xAA
    SendBuff[2] = 0x06;                            // 整帧的长度
    SendBuff[3] = udp_CMD;                         // 命令字
    SendBuff[4] = value;                           // 数据
    SendBuff[5] = CRC8(SendBuff, SendBuff[2] - 1); // CRC8校验值

    // while (RB_ReadBytes(&UART02_RETAINER_BUF, Rx_buf + Datalen, RB_FIFO_MAX_SIZE - Datalen))
    //     ;

    bsp_Send_Bytes(SendBuff, SendBuff[2]); // 发送数据

    for (uint8_t i = 1; i <= again; i++)
    {
        /**************************    等待接收回包的数据  ***************************/
        Datalen = UDP_AwaitReceiveData(Rx_buf);

        /***************************    处理回包中的数据  *********************************/

        if (Datalen >= 4 && CRC8(Rx_buf, Datalen - 1) == Rx_buf[Datalen - 1]) // 数据长度大于等于5，并且CRC8校验OK
        {
            if (Rx_buf[0] != 0xF7 || Rx_buf[1] != 0xAA) // 帧头、地址 校验
            {
                returnValue = UDP_ERR;
            }

            if (Rx_buf[3] == (udp_CMD | 0x80)) // 如果命令字验证正确，进行数据提取
            {
                if (Rx_buf[4] == value)
                {
                    returnValue = UDP_OK;
                    return UDP_OK;
                }
            }
            else
            {
                returnValue = UDP_ERR_CMD;
            }
        }
        if (i == again)
        {
            return UDP_ERR_CRC;
        }

        bsp_Send_Bytes(SendBuff, SendBuff[2]); // 重新发送数据

        returnValue = UDP_ERR_CRC;
    }
    return (returnValue);
}

/*  @brief  设置下位机MCU的状态 MCu打开后带电检测运行
    @param  value
            关闭 、打开   SHUT_s 、OPEN_s
    @param  again
            请求失败后重发次数
    @return 无
    @property 无
*/
UDP_ERR_TYPEDEF UDP_SetObey_EN(SWITCH_E value, uint8_t again)
{
    UDP_ERR_TYPEDEF returnValue; // 返回值
    uint8_t Datalen;

    uint8_t udp_CMD = 0x03; // 命令字
    uint8_t SendBuff[32];   // 待发送的buff

    SendBuff[0] = 0xF7;                            // 帧头
    SendBuff[1] = 0xAA;                            // 地址 这里固定写0xAA
    SendBuff[2] = 0x06;                            // 整帧的长度
    SendBuff[3] = udp_CMD;                         // 命令字
    SendBuff[4] = value;                           // 数据
    SendBuff[5] = CRC8(SendBuff, SendBuff[2] - 1); // CRC8校验值

    // while (RB_ReadBytes(&UART02_RETAINER_BUF, Rx_buf + Datalen, RB_FIFO_MAX_SIZE - Datalen))
    //     ;

    bsp_Send_Bytes(SendBuff, SendBuff[2]); // 发送数据

    for (uint8_t i = 1; i <= again; i++)
    {
        /**************************    等待接收回包的数据  ***************************/
        Datalen = UDP_AwaitReceiveData(Rx_buf);
        /***************************    处理回包中的数据  *********************************/

        if (Datalen >= 4 && CRC8(Rx_buf, Datalen - 1) == Rx_buf[Datalen - 1]) // 数据长度大于等于5，并且CRC8校验OK
        {
            if (Rx_buf[0] != 0xF7 || Rx_buf[1] != 0xAA) // 帧头、地址 校验
            {
                returnValue = UDP_ERR;
            }

            if (Rx_buf[3] == (udp_CMD | 0x80)) // 如果命令字验证正确，进行数据提取
            {
                if (Rx_buf[4] == value)
                {
                    returnValue = UDP_OK;
                    return UDP_OK;
                }
            }
            else
            {
                returnValue = UDP_ERR_CMD;
            }
        }
        if (i == again)
        {
            return UDP_ERR_CRC;
        }

        bsp_Send_Bytes(SendBuff, SendBuff[2]); // 重新发送数据

        returnValue = UDP_ERR_CRC;
    }
    return (returnValue);
}

uint16_t Probe_value = 0;
uint16_t Electric_value = 0;

/*  @brief  定时访问从机
    @return 无
    @property 放在定时器中执行
*/
void Ti_UDP_ReadAllData_event(void)
{
}

void Ti_Probe_Debug_event(void)
{
    // 获取一次全部数据
}

// 调试函数
void UDP_Debug(void)
{
    while (1)
    {
    }
}
